<template>
  <div style="height: 100%; overflow: auto; padding: 20px">
    <fm-generate-form
      :data="JSON.parse(controlData.designData)"
      :remote="remoteFuncs"
      v-model="models"
      :pageAction="pageAction"
      ref="smartform"
      :objectKey="objectKey"
      v-if="!pageLoading"
      @loaded="loadDone"
    >
      <template v-slot:inner>
        <div v-html="vHtml"></div>
      </template>
    </fm-generate-form>

    <iframe
      ref="smartform_jsframe"
      name="smartform_jsframe"
      v-show="false"
    ></iframe>
  </div>
</template>

<script>
import controller from "@/libs/framework/controller";
import _ from "lodash";
import Injection from "@/libs/framework/injection";
import LoaderProxy from "@/libs/framework/loaderProxy";
import user from "@/store/modules/user";
import {smartformDB, queryOne, del, add} from "@/utils/dexie.js";

export default class instance extends controller {
  onBeforeInit() {
    this.urls = {
      model: "/smartform/mobile/hub/",
      save: "/smartform/save",
    };
  }

  onInit() {
    let pageId = this.vm.pageId;
    let pageCode = this.vm.pageCode || this.$params.pageCode;
    let version = this.vm.version;
    let pkey = this.vm.pkey;

    let url = `/smartform/mobile/view/${pageCode}`;
    this.urls.model = url;

    if (pageId) {
      this.setRequestParam("pageId", pageId, "form");
    }
    if (version) {
      this.setRequestParam("version", version, "form");
    }
    if (pkey) {
      _.each(pkey, (v, k) => {
        this.setRequestParam(k, v, "form");
      });
    }
  }

  async getViewModel(conditions, preloader = false) {
    let pageCode = this.vm.pageCode || this.$params.pageCode;
    this.context.pageLoading = true;
    let loading;
    if (preloader) {
      loading = this.vm.appLoading("数据加载中...");
    }

    /**
     * 部分数据由前端进行缓存(cssCode、designData、jsCode、watchProp)
     * 以hasFrontEndCache用于区分是否需要查询缓存数据
     */
      // cacheKey为userId&pageCode
    const isCache = process.env.VUE_APP_SMARTFORM_CACHE === true;
    if(isCache){
      const cacheKey = user.state.userId + "&" + pageCode;
      const cacheData = await queryOne(
        smartformDB,
        "smartformCacheTable",
        "cacheKey",
        cacheKey
      );
      if (!cacheData) {
        this.setRequestParam("hasFrontEndCache", false, "form");
      } else {
        const {cacheCreateTime} = cacheData;
        // cacheCreateTime无效，或者已过期
        if (
          cacheCreateTime == null ||
          parseInt((new Date().getTime() - cacheCreateTime) / 1000 / (60 * 60)) >
          24
        ) {
          this.setRequestParam("hasFrontEndCache", false, "form");
          await del(smartformDB, "smartformCacheTable", "cacheKey", cacheKey);
        } else {
          this.setRequestParam("hasFrontEndCache", true, "form");
        }
      }
    }else{
      this.setRequestParam("hasFrontEndCache", false, "form");
    }
    return new Promise((resolve, reject) => {
      new LoaderProxy(this, conditions).load(resolve, reject, preloader);
    })
      .then(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      })
      .catch(() => {
        this.context.pageLoading = false;
        if (preloader) {
          loading.close();
        }
      });
  }

  async onAfterQuery(type, isSuccess, result) {
    if (isSuccess) {
      // if (result.enums) {
      //   this.vm.$root.enums = result.enums;
      // }
      // if (result.dicts) {
      //   this.vm.$root.dicts = result.dicts;
      // }
      // if (result.controlData) {
      //   this.vm.$root.controlData = result.controlData;
      // }
      if (result.models && result.models.model) {
        let datakey = result.models.model["datakey"];
        result.models.model["datakey"] = datakey || Math.uuid();
      }

      const isCache = process.env.VUE_APP_SMARTFORM_CACHE === true;
      if(isCache){
        const {cssCode, designData, jsCode, watchProp} = result.controlData;
        const {formCode} = result.models.model;
        // cacheKey为userId&formCode
        const cacheKey = user.state.userId + "&" + formCode;
        const cacheData = await queryOne(
          smartformDB,
          "smartformCacheTable",
          "cacheKey",
          cacheKey
        );
        if (cacheData) {
          const {cssCode, designData, jsCode, watchProp} = cacheData;
          Object.assign(result.controlData, {
            cssCode: cssCode,
            designData: designData,
            jsCode: jsCode,
            watchProp: watchProp,
          });
        } else {
          await add(smartformDB, "smartformCacheTable", {
            cacheKey: cacheKey,
            cacheCreateTime: new Date(),
            cssCode: cssCode,
            designData: designData,
            jsCode: jsCode,
            watchProp: watchProp,
          });
        }
      }
    }

    this.vm.loadJs(result);
    this.vm.loadVueMethod(result);

    return result;
  }

  mixin() {
    return {
      props: {
        // 表单相关
        pageId: String,
        pageCode: String,
        version: String | Number,
        // 工作流相关
        appCode: String,
        taskId: String,
        historyTaskId: String,
        assigneeId: String,
        // 主键
        pkey: Object,
      },
      data() {
        return {
          pageLoading: false,
          controlData: {
            formTables: [],
            tableColumns: [],
            tables: [],
            designData: `{
              "list": [],
              "f7list": [],
              "config": {
                "labelWidth": 100,
                "labelPosition": "right",
                "size": "small",
                "customClass": "",
                "ui": "element",
                "layout": "horizontal",
                "labelCol": 3
              },
              "page": {
                "pageId": "",
                "title": "",
                "onVueCreated": "",
                "onVueMounted": ""
              },
              "f7page": {
                "pageContent": true,
                "hideNavbarOnScroll": false,
                "hideToolbarOnScroll": false,
                "ptr": true,
                "infinite": true,
                "onVueCreated": "",
                "onVueMounted": ""
              }
            }`,
          },
          primaryKey: {},
          pageAction: "create",
          jsonData: {},
          editData: {},
          remoteFuncs: {},
          formName: "smartform",
          enums: {},
          dicts: {},
          models: {
            model: {},
          },
          vHtml: "",
          objectKey: "",
        };
      },
      methods: {
        getData() {
          return this.$refs.smartform.getData();
        },

        loadVueMethod(result) {
          let vueMethod = {};
          let frameWindow = this.$refs.smartform_jsframe.contentWindow;

          if (
            result &&
            result.controlData &&
            result.controlData.vueMethod &&
            frameWindow
          ) {
            let vMetText = result.controlData.vueMethod;
            if (!vMetText.startsWith("{")) {
              vMetText = "{" + vMetText + "}";
            }

            vueMethod = JSON.stringify(vMetText, function (key, val) {
              if (typeof val === "function") {
                return val + "";
              }
              return val;
            });
            vueMethod = JSON.parse(vueMethod, function (k, v) {
              if (v.indexOf && v.indexOf("function") > -1) {
                return frameWindow.eval("(function(){return " + v + " })()");
              }
              return v;
            });
          }

          _.each(vueMethod, (value, key) => {
            if (typeof value === "function") {
              this[key] = function () {
                return value(...arguments);
              };
            }
          });
        },
        loadJs(result) {
          result = result || { controlData: {} };
          // 该 htmlClear 方法有问题，希望开发人员写的js不要有XSS风险
          // let js = this.super.$util.htmlClear(result.controlData.jsCode || "");
          let js = result.controlData.jsCode || "";

          let frameWindow = this.$refs.smartform_jsframe.contentWindow;
          if (frameWindow) {
            frameWindow.vue = this;
            frameWindow.data = result;
            Injection.injectSmartformJs(frameWindow);

            const s = frameWindow.document.createElement("script");
            s.type = "text/javascript";
            s.innerHTML = `${js}`;
            frameWindow.document.body.appendChild(s);
          }

          this.objectKey = Math.uuid();
          window[this.objectKey] = frameWindow;
        },
        loadCss() {
          let h = this.super.$util.htmlClear(this.controlData.cssCode || "");
          this.vHtml = `<style> ${h} </style>`;
        },
        loadWatchProp() {
          let watchProp = {};
          let frameWindow = this.$refs.smartform_jsframe.contentWindow;

          if (this.controlData.watchProp && frameWindow) {
            let wpText = this.controlData.watchProp;
            if (!wpText.startsWith("{")) {
              wpText = "{" + wpText + "}";
            }

            watchProp = JSON.stringify(wpText, function (key, val) {
              if (typeof val === "function") {
                return val + "";
              }
              return val;
            });

            watchProp = JSON.parse(watchProp, function (k, v) {
              if (v.indexOf && v.indexOf("function") > -1) {
                return frameWindow.eval("(function(){return " + v + " })()");
              }
              return v;
            });
          }

          let self = this;

          _.each(watchProp, (value, key) => {
            this.$watch(key, function (newVal, oldVal) {
              if (typeof value === "function") {
                value(newVal, oldVal, self);
              }
            });
          });
        },
        loadDone() {
          this.loadCss();
          this.loadWatchProp();

          let $smartform = this.$refs["smartform"];
          // if (
          //   $smartform.data.page.onVueCreated &&
          //   this.$root[$smartform.data.page.onVueCreated]
          // ) {
          //   this.$root[$smartform.data.page.onVueCreated](
          //     $smartform.$refs["elementGenerateForm"]
          //   );
          // }

          // if (
          //   $smartform.data.page.onVueMounted &&
          //   this.$root[$smartform.data.page.onVueMounted]
          // ) {
          //   this.$root[$smartform.data.page.onVueMounted](
          //     $smartform.$refs["elementGenerateForm"]
          //   );
          // }

          $smartform.disabled("all", true);
        },

        getModels() {
          return this.$refs.smartform.models;
        },

        appendPrimaryKey(url, model) {
          if (!model) return url;
          for (let o in model) {
            let joinChar = url.indexOf("?") == -1 ? "?" : "&";
            url += joinChar;
            url += o + "=" + encodeURI(model[o] || "");
          }
          return url;
        },

        close() {
          this.$root.closeModal();
        },

        save() {},
      },

      mounted() {
        this.$once("hook:beforeDestroy", () => {
          if (this.objectKey) {
            window[this.objectKey] = null;
          }
        });
      },
      activated() {
        this.loadJs(this.$data);
        this.loadVueMethod(this.$data);
      },
    };
  }
}
</script>

<style scoped>
</style>
